package com.itttq.im.ws.netty;

import com.itttq.im.common.constant.Constant;
import com.itttq.im.conf.WsProperties;
import com.itttq.im.model.to.MsgTo;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.Attribute;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 心跳机制。心跳分为前端向后端发送心跳、也包括后端检测空闲后向前端发送心跳
 * 前端向后端发送心跳：格式：{"from":null,"to":"SYS","body":null,"type":"HEARTBEAT"}
 *
 * @Author GXG
 */
@Slf4j
@Component
public class HeartBeatHandler extends ChannelInboundHandlerAdapter {

    /**
     * 处理空闲。如果空闲超过指定时间，则关闭通道。未超过则发送心跳给客户端
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // 超时事件：判断evt是否是IdleStateEvent(用于触发用户事件，包含读空闲/写空闲/读写空闲)
        if (evt instanceof IdleStateEvent) {
            //转型
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            // 可能存在设置的时候已经激活。
            Attribute<Long> attribute = ctx.channel().attr(Attributes.IDLE_TIME);
            Long idleTime = attribute.get();
            // 已经超过设置的断开连接
            Long nowTime = System.currentTimeMillis();
            if (null == idleTime) {
                attribute.set(nowTime);
            } else if ((nowTime - idleTime > WsProperties.timeout)) {
                log.info("超时关闭频道，状态：{}，idleTime={}，nowTime={}, timeout = {}", idleStateEvent.state(), idleTime, nowTime, WsProperties.timeout);
                // 关闭通道
                ctx.channel().close();
                return;
            }
            MessageHandler.sendMsg(ctx.channel(), MsgTo.builder().body(Constant.SYSTEM).type(MsgTo.MsgType.HEARTBEAT.getCode()).build());
        }
    }
}
